#include "ftpclient.h"
#include "qftp.h"
#include "qurlinfo.h"
#include "../../ImageAcquisitor/ImageAcquisitor/global.h"

#include <QSettings>
#include <QFile>
#include <QDir>
#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>

FtpClient::FtpClient(QObject *parent) :
    ftp(new QFtp(this)),
    QObject(parent)
{
    tempDir.isValid();
    connect(ftp, SIGNAL(commandFinished(int,bool,QString)),
            this, SLOT(onCmdFinished(int,bool,QString)));
    connect(ftp, SIGNAL(listInfo(QUrlInfo)), this, SLOT(onListInfo(QUrlInfo)));
}

FtpClient::~FtpClient()
{
    ftp->clearPendingCommands();
    QElapsedTimer t;
    t.start();
    while (ftp->hasPendingCommands() && t.elapsed() < 1000);
    ftp->close();
    qDeleteAll(cmdHash.values());
}

void FtpClient::connectFtp()
{
    if (ftp->state() == QFtp::Unconnected) {
        QSettings s(QCoreApplication::applicationDirPath() + "/" + LOCAL_NETWORK_CONFIG, QSettings::IniFormat);
        s.setIniCodec(QSETTINGS_CODEC_NAME);
        QString host = s.value(NETWORK_FTP_HOST).toString();
        int port = s.value(NETWORK_FTP_PORT).toInt();
        QString user = s.value(NETWORK_FTP_USER).toString();
        QString pwd = s.value(NETWORK_FTP_PWD).toString();
        ftp->connectToHost(host, port);
        ftp->login(user, pwd);
    }
}

void FtpClient::onStateChanged(int state)
{

}

void FtpClient::onListInfo(const QUrlInfo &url)
{
    urls += url;
}

void FtpClient::onCmdFinished(int id, bool error, const QString &err)
{
    FTP_ARGS *arg = cmdHash.take(id);
    if (arg) {
        QString msg = arg->cmd;
        if (arg->cmd == "get") {
            if (!error) {
                getHash.insert(arg->remote, arg->local);
                emit downloaded(arg->local);
            }
            msg = QString("%1: %2 <- %3").arg(arg->cmd, arg->local, arg->remote);
        } else if (arg->cmd == "put") {
            msg = QString("%1: %2 -> %3").arg(arg->cmd, arg->local, arg->remote);
            emit uploaded(arg->local);
        } else if (arg->cmd == "list") {
            foreach (const QUrlInfo &url, urls) {
                if (url.isFile()) {
                    QString name = url.name();
                    if (filter.isEmpty() || filter.contains(name.mid(name.lastIndexOf(".")+1)))
                        get(arg->remote + "/" + url.name());
                } else if (url.isDir()) {
                    getAll(arg->remote + "/" + url.name());
                }
            }
            urls.clear();
            msg = "list dir contents: " + arg->remote;
        }

        if (!error) {
            qDebug() << msg;
        } else {
            qCritical() << tr("ftp error: %1: %2").arg(msg, err);
        }

        delete arg;
    }
}

void FtpClient::put(const QString &file, const QString &path)
{
    if (path.isEmpty()) {
        qDebug() << "Ftp put file to null path.";
        return;
    }

    QFile *f = new QFile(file);
    if (f->open(QIODevice::ReadOnly)) {
        connectFtp();
        QString p = path;
        p.replace("\\", "/");
        QStringList subs = p.split("/");
        for (int i = 0; i < subs.size()-1; ++i) {
            ftp->mkdir(subs.at(i));
            ftp->cd(subs.at(i));
        }
        FTP_ARGS *arg = new FTP_ARGS;
        arg->cmd = "put";
        arg->local = file;
        arg->remote = path;
        arg->dev = f;
        int id = ftp->put(f, subs.last());
        cmdHash.insert(id, arg);
        ftp->cd("/");
    } else {
        qCritical() << tr("Open for read failed: %1: %2.").arg(file, f->errorString());
        f->deleteLater();
    }
}

void FtpClient::get(const QStringList &paths)
{
    foreach (const QString &p, paths) {
        if (p.contains("/")) get(p);
        else getAll(p);
    }
}

void FtpClient::get(const QString &path)
{
    if (path.isEmpty()) {
        qDebug() << tr("Ftp get from null path.");
        return;
    }

    QString local = getHash.value(path);
    if (!local.isEmpty()) {
        emit downloaded(local);
        return;
    }

    local = tempDir.path() + "/" + path;
    local.replace("\\", "/");
    QString localDir = local.left(local.lastIndexOf("/"));
    if (!QDir().mkpath(localDir))
        qDebug() << tr("Make dir failed: ") + localDir;
    QFile *f = new QFile(local);
    if (f->open(QIODevice::WriteOnly)) {
        connectFtp();
        FTP_ARGS *arg = new FTP_ARGS;
        arg->cmd = "get";
        arg->local = local;
        arg->remote = path;
        arg->dev = f;
        int id = ftp->get(path, f);
        cmdHash.insert(id, arg);
    } else {
        qCritical() << tr("Open for write failed: %1: %2.").arg(local, f->errorString());
        f->deleteLater();
    }
}

void FtpClient::getAll(const QString &dir)
{
    connectFtp();
    FTP_ARGS *arg = new FTP_ARGS;
    arg->cmd = "list";
    arg->remote = dir;
    int id = ftp->list(dir);
    cmdHash.insert(id, arg);
}
